#ifndef _GHOST_H_
#define _GHOST_H_
#include "Object.h"
#include "PathFinding/BestFirstSearch.h"
#include "PacManGame.h"
#include <iostream>
using namespace std;

struct DistanceHueristic {
	unsigned int operator()( const Object *o1, const Object *o2 ) const
	{ return (unsigned int) (( o1->X - o2->X ) * ( o1->X - o2->X ) + ( o1->Y - o2->Y ) * ( o1->Y - o2->Y )); }
};

struct ManhattanDistanceHueristic {
	unsigned int operator()( const Object *o1, const Object *o2 ) const
	{ return (unsigned int) std::abs( (int) (o1->X - o2->X) ) + std::abs( (int) (o1->Y - o2->Y) ); }
};

struct ObjectSuccessors {
	std::vector<Object *> operator()( const Object *o ) const
	{
		assert( o != NULL );
		std::vector<Object *> successors;

		for( int i = -1; i <= 1; i += 2 )
		{
			int successorY = o->Y;
			int successorX = o->X + i;

			//if( successorY < 0 ) continue;
			//if( successorX < 0 ) continue;
			//if( successorY >= Game::GAME_BOARD_SIZE ) continue;
			//if( successorX >= Game::GAME_BOARD_SIZE ) continue;
			if( successorY < 0 ) successorY = Game::GAME_BOARD_SIZE - 1;
			if( successorX < 0 ) successorX = Game::GAME_BOARD_SIZE - 1;
			if( successorY >= Game::GAME_BOARD_SIZE ) successorY = 0;
			if( successorX >= Game::GAME_BOARD_SIZE ) successorX = 0;

			int index = successorY * Game::GAME_BOARD_SIZE + successorX;

			if( Game::gameBoard[ index ]->type != Object::OBJ_BLOCK )
				successors.push_back( Game::gameBoard[ index ] );
		}	
		
		for( int j = -1; j <= 1; j += 2 )
		{
			int successorY = o->Y + j;
			int successorX = o->X;

			if( successorY < 0 ) continue;
			if( successorX < 0 ) continue;
			if( successorY >= Game::GAME_BOARD_SIZE ) continue;
			if( successorX >= Game::GAME_BOARD_SIZE ) continue;

			int index = successorY * Game::GAME_BOARD_SIZE + successorX;

			if( Game::gameBoard[ index ]->type != Object::OBJ_BLOCK )
				successors.push_back( Game::gameBoard[ index ] );
		}
		
		assert( successors.size( ) <= 4 );
		return successors;
	}
};


class Ghost : public Object
{
  public:

	typedef enum tagGhostState {
		SEEKING_PACMAN,
		FLEEING_PACMAN,
		SCATTER,
		DEAD
	} GhostState;

  protected:
	  typedef struct tagPathChoice {
		  Object *path;
		  float hueristic;

		  bool operator<( const struct tagPathChoice &pc ) const
		  { return hueristic < pc.hueristic; }

		  bool operator>( const struct tagPathChoice &pc ) const
		  { return hueristic > pc.hueristic; }

	  } PathChoice;

	unsigned int nGhostId;
	GhostState state;
	

	BestFirstSearch<Object *, ManhattanDistanceHueristic, ObjectSuccessors> bestFirstSearch;


	void moveUp( );	
	void moveDown( );
	void moveLeft( );
	void moveRight( );
	Object *_findPath( );
	Object *_findPath( const Object *pStart, const Object *pEnd );
	Object *_findPath( int offsetX, int offsetY );
	void _pathCleanup( );

	virtual void flee( );
	virtual void seek( );
	void returnToHome( );
	void _render( int nTexture );
	void render( int nTexture );

  public:
	GhostState getState( ) const;
	void setState( GhostState s );

	Ghost( int id );
	
	static bool isCollision( Object *pObj, Ghost *pGhost );

	static void setAllGhostToFlee( );
	static void setAllGhostToSeek( );

};


#endif